﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Expressions;

namespace Apps.Common
{
    public class TransHelper
    {
        //示例：StudentSecond ss= TransHelper.TransExp<Student, StudentSecond>(s);
        private static Dictionary<string, object> _Dic = new Dictionary<string, object>();
        public static TOut TransExp<TIn, TOut>(TIn tIn)
        {
            try
            {
                string key = string.Format("trans_exp_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
                if (!_Dic.ContainsKey(key))
                {
                    ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                    List<MemberBinding> memberBindingList = new List<MemberBinding>();

                    foreach (var item in typeof(TOut).GetProperties())
                    {

                        if (!item.CanWrite)
                            continue;
                        var inProperty = typeof(TIn).GetProperty(item.Name);
                        if (inProperty == null)
                        {
                            //输入类中没有该属性，不复制
                            continue;
                        }
                        if (inProperty.PropertyType.FullName != item.PropertyType.FullName)
                        {
                            //字段类型不一至
                            throw new FormatException($"对象复制时错误，属性{inProperty.Name}的类型不一至");
                        }
                        MemberExpression property = Expression.Property(parameterExpression, inProperty);
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }

                    MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                    Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
                    Func<TIn, TOut> func = lambda.Compile();

                    _Dic[key] = func;
                }
                return ((Func<TIn, TOut>)_Dic[key])(tIn);
            }
            catch (Exception err)
            {
                throw err;
            }
        }

        public static List<TOut> TransExpList<TIn, TOut>(IList<TIn> inValList)
        {
            List<TOut> retVal = new List<TOut>();
            foreach (var inVal in inValList)
            {
                retVal.Add(TransExp<TIn, TOut>(inVal));
            }
            return retVal;
        }
    }
}
